package com.ler.yrmall.cart.service.impl;

import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON;
import com.ler.yrmall.dto.LoginUser;
import com.ler.yrmall.enums.ErrorCodeEnum;
import com.ler.yrmall.exception.BusinessException;
import com.ler.yrmall.utils.SecurityUtils;
import com.ler.yrmall.cart.dto.CartDTO;
import com.ler.yrmall.cart.dto.CartItemDTO;
import com.ler.yrmall.cart.service.CartService;
import com.ler.yrmall.product.api.ProductApi;
import com.ler.yrmall.product.dto.SkuDTO;
import com.ler.yrmall.basic.Result;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author leron
 */
@Service
public class CartServiceImpl implements CartService {

    private static final String CART_PREFIX = "yuruomall:cart:";

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private ProductApi productApi;

    @Override
    public void addCart(Long skuId, Integer num) {
        // TODO 改为多线程
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        CartItemDTO cartItem = new CartItemDTO();
        String res = (String) cartOps.get(skuId.toString());
        if (StringUtils.isEmpty(res)) {
            //查询商品信息
            Result<SkuDTO> skuResult = productApi.getSkuById(skuId);
            SkuDTO sku = skuResult.getData();
            cartItem.setCount(num);
            cartItem.setChecked(true);
            cartItem.setSkuId(skuId);
            cartItem.setSpuId(sku.getSpuId());
            cartItem.setSpuTitle(sku.getName());
            cartItem.setImage(sku.getCover());
            cartItem.setPrice(sku.getPrice());
            Result<List<String>> attrResponse = productApi.getAttrsAsString(skuId);
            Assert.isTrue(attrResponse.isSuccess(),() -> new BusinessException(ErrorCodeEnum.ADD_CART_ERROR));
            cartItem.setSkuAttr(attrResponse.getData());
        } else {
            //叠加数量
            cartItem = JSON.parseObject(res, CartItemDTO.class);
            cartItem.setCount(cartItem.getCount() + num);
        }
        cartOps.put(skuId.toString(), JSON.toJSONString(cartItem));
    }

    @Override
    public void deleteCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.delete(skuId.toString());
    }

    @Override
    public void checkedChange(long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String res = (String) cartOps.get(String.valueOf(skuId));
        if (StringUtils.isNotBlank(res)) {
            CartItemDTO cartItem = JSON.parseObject(res, CartItemDTO.class);
            cartItem.setChecked(!cartItem.getChecked());
            cartOps.put(String.valueOf(skuId), JSON.toJSONString(cartItem));
        }
    }

    @Override
    public void checkAllChange() {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        List<Object> values = cartOps.values();
        List<CartItemDTO> cartList = Optional.ofNullable(values).map(List::stream).orElse(Stream.empty()).map(item -> {
            String str = (String) item;
            return JSON.parseObject(str, CartItemDTO.class);
        }).collect(Collectors.toList());
        List<CartItemDTO> notChecked = cartList.stream().filter(item -> !item.getChecked()).collect(Collectors.toList());
        boolean checkedAll = notChecked.size() > 0;
        cartList.forEach(item -> item.setChecked(checkedAll));
        cartList.forEach(item -> {
            cartOps.delete(item.getSkuId().toString());
            cartOps.put(item.getSkuId().toString(),JSON.toJSONString(item));
        });
    }

    @Override
    public CartItemDTO getCartItem(String skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String cart = (String) cartOps.get(skuId);
        return JSON.parseObject(cart, CartItemDTO.class);
    }

    @Override
    public CartDTO getCartList() {
        CartDTO cart = new CartDTO();
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        List<CartItemDTO> values =
                Objects.requireNonNull(cartOps.values()).stream().map(item -> JSON.parseObject((String) item, CartItemDTO.class)).collect(Collectors.toList());
        cart.setItems(values);
        return cart;
    }

    public BoundHashOperations<String, Object, Object> getCartOps() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        return stringRedisTemplate.boundHashOps(CART_PREFIX + loginUser.getId());
    }
}
